/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * https://zhiqim.org/project/zhiqim_framework/zhiqim_zml.htm
 *
 * Zhiqim Zml is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.zml.statement;

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

import org.zhiqim.kernel.model.maps.HashMapSO;
import org.zhiqim.kernel.model.maps.MapSO;
import org.zhiqim.kernel.util.Strings;
import org.zhiqim.kernel.util.Types;
import org.zhiqim.kernel.util.Validates;
import org.zhiqim.zml.Expression;
import org.zhiqim.zml.ExpressionParser;
import org.zhiqim.zml.Statement;
import org.zhiqim.zml.StatementNesting;
import org.zhiqim.zml.StatementParser;
import org.zhiqim.zml.ZmlVariable;
import org.zhiqim.zml.Zmls;
import org.zhiqim.zml.exception.StatementException;
import org.zhiqim.zml.statement._Return.ReturnException;

/**
 * 判断语句，格式为：<#if a=1>内容1<#elseif a==2>内容2<#elseif a==3>内容3<#else>其他内容<#if>
 *
 * @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
 */
public class _If extends Statement implements StatementNesting
{
    private Expression _ifExpression;                               //if表达式
    private boolean ifHasVar;                                       //if语名中是否有定义变量语句
    private List<Statement> ifStmtList;                              //if语句列表
    private List<_ElseIf> elseIfList = new ArrayList<_ElseIf>();     //elseif列表
    private _Else _else;                                             //else
    private boolean isBeginExclusiveLine;
    
    private transient String content;
    private transient int contentBeginIndex;
    
    @Override
    public boolean isNesting()
    {
        return true;
    }
    
    @Override
    public boolean isExclusiveLine() throws StatementException
    {
        return super.isExclusiveLine()?isBeginExclusiveLine:false;
    }
    
    @Override
    public void parseStatement() throws StatementException
    {
        String s = Strings.trim(getStatement(), IF_BEGIN, IF_END);
        int ind = s.indexOf(TAG_END);
        if (ind == -1)
            throw new StatementException(this, IF + "未找到单行结束符");

        try
        {
            String expression = s.substring(0, ind).trim();
            _ifExpression = ExpressionParser.parseExpression(expression);
        }
        catch(Exception e)
        {
            throw new StatementException(getPath(), getBeginLine(), getBeginColumn(), IF + e.getMessage());
        }
        
        //对if内的内容进行嵌套检查，得到嵌套语句列表，默认isBeginExclusiveLine取值在<#if>中<#elseif>和<#else>在process时重设置
        content = s.substring(ind + 1);
        int brNum = Strings.getStartsWithBrNum(content);
        if (brNum > 0)
        {//删除<#if>之后的首个\r\n
            content = content.substring(brNum);
        }
        
        isBeginExclusiveLine = brNum > 0;
        contentBeginIndex = getBeginIndex() + IF_BEGIN.length() + ind + 1 + brNum;
        
        ifStmtList = StatementParser.parseStatementNesting(this);
        content = null;//清除临时数据
        
        //再对列表中_Html语句查找到<#elseif>和<#else>
        boolean isElse = false;//先找<#else>
        for (ListIterator<Statement> it=ifStmtList.listIterator();it.hasNext();)
        {
            Statement ts = it.next();
            if (isElse)
            {//如果找到else，则后面的语句全交给else处理
                it.remove();
                _else.addStatement(ts);
                continue;
            }
            
            //没有到else，则查找_Html中
            if (!(ts instanceof _Text))
                continue;
            
            _Text _html = (_Text)ts;
            String statement = _html.getStatement();
            int indElse = statement.indexOf(IF_ELSE);
            if (indElse != -1)
            {//找到
                isElse = true;
                _else = new _Else();
                
                //拆开_html
                it.remove();
                
                String statement1 = statement.substring(0, indElse);
                if (!Validates.isEmpty(statement1))
                {
                    _Text _html1 = new _Text();
                    _html1.setStatement(getZml(), _If.this, statement1);
                    _html1.setIndexInner(0, indElse);
                    _html1.setIndexAll(_html.getBeginIndex(), _html.getBeginIndex()+indElse);
                    
                    it.add(_html1);
                }
                
                String statement2 = statement.substring(indElse + IF_ELSE.length());//把<#else>过滤掉，不需要表达式
                if (!Validates.isEmpty(statement2))
                {
                    _Text _html2 = new _Text();
                    _html2.setStatement(getZml(), _If.this, statement2);
                    _html2.setIndexInner(indElse + IF_ELSE.length(), statement.length());
                    _html2.setIndexAll(_html.getBeginIndex() + indElse + IF_ELSE.length(), _html.getEndIndex());
                    _else.addStatement(_html2);
                }
            }
        }
        
        //再查找<#elseif>
        boolean isElseIf = false;_ElseIf _elseif = null;
        for (ListIterator<Statement> it=ifStmtList.listIterator();it.hasNext();)
        {
            Statement ts = it.next();
            if (isElseIf)
            {//如果正在处理一个elseif时，检查是否到了另一个elseif
                if (!(ts instanceof _Text))
                {
                    it.remove();
                    _elseif.addStatement(ts);
                    continue;
                }
                
                //在<#elseif中，从<#if删除
                it.remove();
                
                _Text _html = (_Text)ts;
                String statement = _html.getStatement();
              
                //判断是否有下一个
                int indElseIf = statement.indexOf(IF_ELSEIF);
                if (indElseIf == -1)
                {//没有下一个，整个表达式都是<#elseif
                    _elseif.addStatement(ts);
                    continue;
                }
                
                //把前面的还给上一个<#elseif
                String statement1 = statement.substring(0, indElseIf);
                if (!Validates.isEmpty(statement1))
                {
                    _Text _html1 = new _Text();
                    _html1.setStatement(getZml(), _If.this, statement1);
                    _html1.setIndexInner(0, indElseIf);
                    _html1.setIndexAll(_html.getBeginIndex(), _html.getBeginIndex()+indElseIf);
                    _elseif.addStatement(_html1);
                }
                
                //新的一个开始
                _elseif = new _ElseIf();
                elseIfList.add(_elseif);
                
                while(true)
                {//判断新的一个下面还有没有
                    int indElseIf2 = statement.indexOf(IF_ELSEIF, indElseIf + IF_ELSEIF.length());
                    if (indElseIf2 == -1)
                    {//没有下一个
                        String statement2 = statement.substring(indElseIf);
                        if (!Validates.isEmpty(statement2))
                        {
                            _Text _html2 = new _Text();
                            _html2.setStatement(getZml(), _If.this, statement2);
                            _html2.setIndexInner(indElseIf, indElseIf + statement2.length());
                            _html2.setIndexAll(_html.getBeginIndex()+indElseIf, _html.getBeginIndex()+indElseIf+statement2.length());
                            
                            _elseif.addStatement(_html2);
                        }
                        break;
                    }
                    
                    //有下一个
                    String statement2 = statement.substring(indElseIf, indElseIf2);
                    if (!Validates.isEmpty(statement2))
                    {
                        _Text _html2 = new _Text();
                        _html2.setStatement(getZml(), _If.this, statement2);
                        _html2.setIndexInner(indElseIf, indElseIf + statement2.length());
                        _html2.setIndexAll(_html.getBeginIndex()+indElseIf, _html.getBeginIndex()+indElseIf+statement2.length());
                        
                        _elseif.addStatement(_html2);
                    }
                    
                    //定义下一个
                    _elseif = new _ElseIf();
                    elseIfList.add(_elseif);
                    indElseIf = indElseIf2;
                }
            }
            else
            {//如果没有处理，则查找
                if (!(ts instanceof _Text))
                    continue;
                
                _Text _html = (_Text)ts;
                String statement = _html.getStatement();
                int indElseIf = statement.indexOf(IF_ELSEIF);
                if (indElseIf == -1)
                    continue;
                
                //找到<#elseif>,拆开_html
                it.remove();
                
                //<#elseif>之前的，还给<#if>
                String statement1 = statement.substring(0, indElseIf);
                if (!Validates.isEmpty(statement1))
                {
                    _Text _html1 = new _Text();
                    _html1.setStatement(getZml(), _If.this, statement1);
                    _html1.setIndexInner(0, indElseIf);
                    _html1.setIndexAll(_html.getBeginIndex(), _html.getBeginIndex()+indElseIf);
                    
                    it.add(_html1);
                }

                //第一个开始
                _elseif = new _ElseIf();
                elseIfList.add(_elseif);
                isElseIf = true;
                
                while(true)
                {
                    int indElseIf2 = statement.indexOf(IF_ELSEIF, indElseIf + IF_ELSEIF.length());
                    if (indElseIf2 == -1)
                    {//没有下一个
                        String statement2 = statement.substring(indElseIf);
                        if (!Validates.isEmpty(statement2))
                        {
                            _Text _html2 = new _Text();
                            _html2.setStatement(getZml(), _If.this, statement2);
                            _html2.setIndexInner(indElseIf, indElseIf + statement2.length());
                            _html2.setIndexAll(_html.getBeginIndex()+indElseIf, _html.getBeginIndex()+indElseIf+statement2.length());
                            
                            _elseif.addStatement(_html2);
                        }
                        break;
                    }
                    
                    //有下一个
                    String statement2 = statement.substring(indElseIf, indElseIf2);
                    if (!Validates.isEmpty(statement2))
                    {
                        _Text _html2 = new _Text();
                        _html2.setStatement(getZml(), _If.this, statement2);
                        _html2.setIndexInner(indElseIf, indElseIf + statement2.length());
                        _html2.setIndexAll(_html.getBeginIndex()+indElseIf, _html.getBeginIndex()+indElseIf+statement2.length());
                        
                        _elseif.addStatement(_html2);
                    }
                    
                    //定义下一个
                    _elseif = new _ElseIf();
                    elseIfList.add(_elseif);
                    indElseIf = indElseIf2;
                }
            }
        }
        
        for (_ElseIf elseif : elseIfList)
        {
            elseif.parseStatement();
        }
        
        ifHasVar = StatementParser.hasVar(ifStmtList);
    }
    
    @Override
    public String process(ZmlVariable variableMap) throws StatementException
    {
        Object value = null;
        
        try
        {
            value = _ifExpression.build(variableMap);
        }
        catch(Exception e)
        {
            throw new StatementException(this, IF + e.getMessage(), e);
        }
        
        //表达式为null表示不检查所有的if,elseif,else，如item.isTrue()时item==null导致方法返回null
        if (value == null)
            return null;
        
        //不是null，则检查是不是布尔型，如果不是报异常
        if (!Types.isBoolean(value))
            throw new StatementException(this, IF + "中表达式"+_ifExpression+"，格式不正确，不是布尔型");
        
        try
        {
            //<#if>
            if ((Boolean)value)
            {
                if (ifHasVar)
                {
                    //定义局部变量
                    MapSO localMap = new HashMapSO(2);
                    variableMap.addLocalVariable(localMap);
                    
                    try
                    {
                        StringBuilder strb = new StringBuilder();
                        StatementParser.processStatementList(ifStmtList, variableMap, strb);
                        return Zmls.removeRightMaybeEmptyBlankLine(strb.toString());
                    }
                    finally
                    {//清除局部变量
                        variableMap.removeLocalVariable(localMap);
                        localMap.clear();localMap = null;
                    }
                }
                else
                {
                    StringBuilder strb = new StringBuilder();
                    StatementParser.processStatementList(ifStmtList, variableMap, strb);
                    return Zmls.removeRightMaybeEmptyBlankLine(strb.toString());
                }
            }
            
            //<#elseif>
            for (_ElseIf elseif : elseIfList)
            {
                if (elseif.is(variableMap))
                    return elseif.process(variableMap);
            }
            
            //<#else>
            if (_else == null)
                return null;
            else
                return _else.process(variableMap);
        }
        catch(ReturnException e)
        {//通过异常方式给外面的函数提供返回值
            throw e;
        }
        catch(StatementException e)
        {
            throw new StatementException(this, IF + e.getMessage(), e);
        }
        
        //</#if>
    }

    /**********************************************/
    //两个临时数据，用于语句解析成嵌套语句列表
    /**********************************************/
    
    @Override
    public String getContent()
    {
        return content;
    }
    @Override
    public int getContentBeginIndex()
    {
        return contentBeginIndex;
    }
    
    @Override
    public String getPrevStatement(Statement stmt) throws StatementException
    {
        List<Statement> stmtList = getStatementList(stmt);
        if (stmtList == null)
            return null;
        
        int ind = stmtList.indexOf(stmt);
        if (ind <= 0)
            return null;
        
        return stmtList.get(ind-1).getStatement();
    }
    
    @Override
    public String getNextStatement(Statement stmt) throws StatementException
    {
        List<Statement> stmtList = getStatementList(stmt);
        if (stmtList == null)
            return null;
        
        int ind = stmtList.indexOf(stmt);
        if (ind == -1 || ind >= stmtList.size()-1)
            return null;
        
        return stmtList.get(ind+1).getStatement();
    }
    
    /** 获取语句所有的语句列表 */
    private List<Statement> getStatementList(Statement stmt)
    {
        if (ifStmtList.contains(stmt))
            return ifStmtList;

        for (_ElseIf elseif : elseIfList)
        {
            if (elseif.elseifStmtList.contains(stmt))
                return elseif.elseifStmtList;
        }
        
        if (_else.elseStmtList.contains(stmt))
            return _else.elseStmtList;
        
        return null;
    }
    
    /**********************************************/
    //定义两个私有类 _ElseIf _Else
    /**********************************************/
    
    /** <#if>语句中的<#elseif>部分 */
    private class _ElseIf
    {
        private Expression _elseifExpression;       //表达式
        private List<Statement> elseifStmtList;       //嵌套语句列表
        private boolean elseifHasVar;               //是否有变量定义语句
        
        _ElseIf()
        {
            elseifStmtList = new ArrayList<Statement>();
        }
        
        void parseStatement() throws StatementException
        {
            _Text _html = (_Text)elseifStmtList.remove(0);
            String s = _html.getStatement();
            s = s.substring(IF_ELSEIF.length());
            int ind = s.indexOf(">");
            if (ind == -1)
                throw new StatementException(getPath(), getBeginLine(), getBeginColumn(), ELSEIF + "未找到单行结束符");
            
            try
            {
                String expression = s.substring(0, ind);
                _elseifExpression = ExpressionParser.parseExpression(expression);
            }
            catch(Exception e)
            {
                throw new StatementException(getPath(), getBeginLine(), getBeginColumn(), ELSEIF + e.getMessage());
            }
            
            String statement = s.substring(ind+1);
            if (!Validates.isEmpty(statement))
            {//表达式后面的内容
                _Text firstHtml = new _Text();
                firstHtml.setStatement(getZml(), _If.this, statement);
                firstHtml.setIndexInner(ind+1, statement.length());
                firstHtml.setIndexAll(getBeginIndex()+ind+1, getEndIndex());
                
                elseifStmtList.add(0, firstHtml);
            }
            
            elseifHasVar = StatementParser.hasVar(elseifStmtList);
        }

        String process(ZmlVariable variableMap) throws StatementException
        {
            if (elseifHasVar)
            {
                //定义局部变量
                MapSO localMap = new HashMapSO(2);
                variableMap.addLocalVariable(localMap);
                
                try
                {
                    StringBuilder strb = new StringBuilder();
                    StatementParser.processStatementList(elseifStmtList, variableMap, strb);
                    String result = strb.toString();
                    int brNum = Strings.getStartsWithBrNum(result);
                    if (brNum > 0)
                    {
                        isBeginExclusiveLine = true;
                        result = result.substring(brNum);
                    }
                    result = Zmls.removeRightMaybeEmptyBlankLine(result);
                    return result;
                }
                finally
                {//清除局部变量
                    variableMap.removeLocalVariable(localMap);
                    localMap.clear();localMap = null;
                }
            }
            else
            {
                StringBuilder strb = new StringBuilder();
                StatementParser.processStatementList(elseifStmtList, variableMap, strb);
                String result = strb.toString();
                int brNum = Strings.getStartsWithBrNum(result);
                if (brNum > 0)
                {
                    isBeginExclusiveLine = true;
                    result = result.substring(brNum);
                }
                result = Zmls.removeRightMaybeEmptyBlankLine(result);
                return result;
            }
        }
        
        boolean is(ZmlVariable variableMap) throws StatementException
        {
            Object value = null;
            
            try
            {
                value = _elseifExpression.build(variableMap);
            }
            catch(Exception e)
            {
                throw new StatementException(getPath(), getBeginLine(), getBeginColumn(), ELSEIF + e.getMessage(), e);
            }
            
            if (!Types.isBoolean(value))
                throw new StatementException(getPath(), getBeginLine(), getBeginColumn(), ELSEIF + "中表达式"+_elseifExpression+"，格式不正确，不是布尔型");
            
            return (Boolean)value;
        }
        
        void addStatement(Statement statement)
        {
            elseifStmtList.add(statement);
        }
    }
    
    /** <#if>语句中的<#else>部分 */
    private class _Else
    {
        private List<Statement> elseStmtList; //嵌套的语句列表
        private boolean elseHasVar;         //是否包括定义变量语句
        
        _Else()
        {
            elseStmtList = new ArrayList<Statement>();
        }
        
        String process(ZmlVariable variableMap) throws StatementException
        {
            if (elseHasVar)
            {
                //定义局部变量
                MapSO localMap = new HashMapSO(2);
                variableMap.addLocalVariable(localMap);
                
                try
                {
                    StringBuilder strb = new StringBuilder();
                    StatementParser.processStatementList(elseStmtList, variableMap, strb);
                    String result = strb.toString();
                    int brNum = Strings.getStartsWithBrNum(result);
                    if (brNum > 0)
                    {
                        isBeginExclusiveLine = true;
                        result = result.substring(brNum);
                    }
                    result = Zmls.removeRightMaybeEmptyBlankLine(result);
                    return result;
                }
                finally
                {//清除局部变量
                    variableMap.removeLocalVariable(localMap);
                    localMap.clear();localMap = null;
                }
                
            }
            else
            {
                StringBuilder strb = new StringBuilder();
                StatementParser.processStatementList(elseStmtList, variableMap, strb);
                String result = strb.toString();
                int brNum = Strings.getStartsWithBrNum(result);
                if (brNum > 0)
                {
                    isBeginExclusiveLine = true;
                    result = result.substring(brNum);
                }
                result = Zmls.removeRightMaybeEmptyBlankLine(result);
                return result;
            }
        }
        
        void addStatement(Statement statement)
        {
            elseStmtList.add(statement);
            
            if (!elseHasVar && (statement instanceof _Var))
                elseHasVar = true;
        }
    }
}
